/*
Copyright 2017 yangchong211（github.com/yangchong211）

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package com.yc.video.surface;

import ohos.agp.components.Component;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.components.surfaceprovider.SurfaceProvider;
import ohos.agp.graphics.Surface;
import ohos.agp.graphics.SurfaceOps;
import ohos.agp.window.service.WindowManager;
import ohos.app.Context;

import com.yc.kernel.inter.AbstractVideoPlayer;

/**
 * <pre>
 *     @author yangchong
 *     blog  : https://github.com/yangchong211
 *     time  : 2018/9/21
 *     desc  : 重写SurfaceView，适配视频的宽高和旋转
 *     revise:
 * </pre>
 */
public class RenderSurfaceView extends SurfaceProvider implements InterSurfaceView,
    Component.BindStateChangedListener, Component.EstimateSizeListener {
    /**
     * 优点：可以在一个独立的线程中进行绘制，不会影响主线程；使用双缓冲机制，播放视频时画面更流畅
     * 缺点：Surface不在View hierachy中，它的显示也不受View的属性控制，所以不能进行平移，缩放等变换，
     * 也不能放在其它ViewGroup中。SurfaceView 不能嵌套使用。
     * <p>
     * SurfaceView双缓冲
     * 1.SurfaceView在更新视图时用到了两张Canvas，一张frontCanvas和一张backCanvas。
     * 2.每次实际显示的是frontCanvas，backCanvas存储的是上一次更改前的视图，当使用lockCanvas（）获取画布时，
     * 得到的实际上是backCanvas而不是正在显示的frontCanvas，之后你在获取到的backCanvas上绘制新视图，
     * 再unlockCanvasAndPost（canvas）此视图，那么上传的这张canvas将替换原来的frontCanvas作为新的frontCanvas，
     * 原来的frontCanvas将切换到后台作为backCanvas。
     */

    private MeasureHelper mMeasureHelper;
    private AbstractVideoPlayer mMediaPlayer;

    public RenderSurfaceView(Context context) {
        super(context);
        init(context);
    }

    @Override
    public void onComponentBoundToWindow(Component component) {
    }

    @Override
    public void onComponentUnboundFromWindow(Component component) {
        if (callback != null) {
            getSurfaceOps().get().removeCallback(callback);
        }
    }

    @Override
    public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {
        int[] measuredSize = mMeasureHelper.doMeasure(widthMeasureSpec, heightMeasureSpec);
        setEstimatedSize(
            Component.EstimateSpec.getChildSizeWithMode(measuredSize[0], measuredSize[0], Component.EstimateSpec.PRECISE),
            Component.EstimateSpec.getChildSizeWithMode(measuredSize[1], measuredSize[1], Component.EstimateSpec.PRECISE));
        return true;
    }

    private void init(Context context) {
        setBindStateChangedListener(this);
        setEstimateSizeListener(this);
        pinToZTop(false);
        WindowManager.getInstance().getTopWindow().get().setTransparent(true);
        mMeasureHelper = new MeasureHelper();
        SurfaceOps holder = this.getSurfaceOps().get();
        holder.addCallback(callback);
    }

    /**
     * 关联AbstractPlayer
     *
     * @param player player
     */
    @Override
    public void attachToPlayer(AbstractVideoPlayer player) {
        this.mMediaPlayer = player;
    }

    /**
     * 设置视频宽高
     *
     * @param videoWidth 宽
     * @param videoHeight 高
     */
    @Override
    public void setVideoSize(int videoWidth, int videoHeight) {
        if (videoWidth > 0 && videoHeight > 0) {
            mMeasureHelper.setVideoSize(videoWidth, videoHeight);
            postLayoutUI();
        }
    }

    /**
     * 设置视频旋转角度
     *
     * @param degree 角度值
     */
    @Override
    public void setVideoRotation(int degree) {
        mMeasureHelper.setVideoRotation(degree);
        setRotation(degree);
    }

    /**
     * 设置screen scale type
     *
     * @param scaleType 类型
     */
    @Override
    public void setScaleType(int scaleType) {
        mMeasureHelper.setScreenScale(scaleType);
        postLayoutUI();
    }

    /**
     * 获取真实的RenderView
     *
     * @return view
     */
    @Override
    public Component getView() {
        return this;
    }

    /**
     * 截图
     *
     * @return bitmap
     */
    @Override
    public PixelMapElement doScreenShot() {
        return null;
    }

    /**
     * 释放资源
     */
    @Override
    public void release() {
        if (callback != null) {
            getSurfaceOps().get().removeCallback(callback);
        }
    }

    /**
     * 记得一定要重新写这个方法，如果角度发生了变化，就重新绘制布局
     * 设置视频旋转角度
     *
     * @param rotation 角度
     */
    @Override
    public void setRotation(float rotation) {
        if (rotation != getRotation()) {
            super.setRotation(rotation);
            postLayoutUI();
        }
    }

    private void postLayoutUI() {
        mContext.getUITaskDispatcher().asyncDispatch(new Runnable() {
            @Override
            public void run() {
                postLayout();
            }
        });
    }

    SurfaceOps.Callback callback = new SurfaceOps.Callback() {
        /**
         * 创建的时候调用该方法
         * @param surfaceOps                        holder
         */
        @Override
        public void surfaceCreated(SurfaceOps surfaceOps) {
            if (mMediaPlayer != null) {
                Surface surface = surfaceOps.getSurface();
                mMediaPlayer.setSurface(surface);
            }
        }

        /**
         * 视图改变的时候调用方法
         * @param surfaceOps
         * @param format
         * @param width
         * @param height
         */
        @Override
        public void surfaceChanged(SurfaceOps surfaceOps, int format, int width, int height) {
        }

        /**
         * 销毁的时候调用该方法
         * @param surfaceOps
         */
        @Override
        public void surfaceDestroyed(SurfaceOps surfaceOps) {
        }
    };
}
